#include "devicefactory.h"

#include <FunctionDiscoveryKeys_devpkey.h>

DeviceFactory::DeviceFactory(QObject * parent)
	: QObject(parent),
	  IMMNotificationClient(),
	  device_enum(NULL)
	{
	}

DeviceFactory::~DeviceFactory()
	{
		device_enum->UnregisterEndpointNotificationCallback(this);
	}

ULONG DeviceFactory::AddRef()
	{
		return InterlockedIncrement(&c_ref);
	}

IMMDevice * DeviceFactory::getDeviceById(LPCWSTR device_id)
	{
		IMMDevice * device = NULL;
		if (device_enum != NULL)
			device_enum->GetDevice(device_id, &device);
		return device;
	}

LPGUID DeviceFactory::getDeviceId(IMMDevice *)
{
	return NULL;
}

QString DeviceFactory::getDeviceName(IMMDevice * device)
	{
		QString name;
		LPWSTR device_name;
		HRESULT hr;
		IPropertyStore * props;

		hr = device->GetId(&device_name);
		if (FAILED(hr))
			return name;

		hr = device->OpenPropertyStore(STGM_READ, &props);
		if (FAILED(hr))
			return name;

		PROPVARIANT var_name;
		PropVariantInit(&var_name);

		hr = props->GetValue(PKEY_Device_FriendlyName, &var_name);
		if (FAILED(hr))
			return name;

		name = QString::fromWCharArray((wchar_t *)var_name.pwszVal);

		PropVariantClear(&var_name);
		SAFE_RELEASE(props)

		return name;
	}

HRESULT DeviceFactory::OnDefaultDeviceChanged(EDataFlow flow, ERole, LPCWSTR device_id)
	{
		IMMDevice * device = getDeviceById(device_id);
		QString dev_name = getDeviceName(device);
		QString dev_type;

		if (flow == eCapture)
			dev_type = "eCapture";
		else if (flow == eRender)
			dev_type = "eRender";

		emit defaultDeviceChanged(dev_name, dev_type);
		SAFE_RELEASE(device)

		return S_OK;
	}

HRESULT DeviceFactory::OnDeviceAdded(LPCWSTR device_id)
{
	qDebug(__FUNCTION__);
	emit deviceAdded(device_id);
	return S_OK;
}

HRESULT DeviceFactory::OnDeviceRemoved(LPCWSTR device_id)
{
	qDebug(__FUNCTION__);
	emit deviceRemoved(device_id);
	return S_OK;
}

HRESULT DeviceFactory::OnDeviceStateChanged(LPCWSTR, DWORD)
	{ return S_OK; }

HRESULT DeviceFactory::OnPropertyValueChanged(LPCWSTR, const PROPERTYKEY)
	{ return S_OK; }

HRESULT DeviceFactory::QueryInterface(REFIID riid, void ** p_interface)
	{
		if (IID_IUnknown == riid)
		{
			AddRef();
			*p_interface = (IUnknown *)this;
		}

		else if (__uuidof(IMMNotificationClient) == riid)
		{
			AddRef();
			*p_interface = (IMMNotificationClient *)this;
		}

		else
		{
			*p_interface = NULL;
			return E_NOINTERFACE;
		}

		return S_OK;
	}

ULONG DeviceFactory::Release()
	{
		ULONG ul_ref = InterlockedDecrement(&c_ref);
		if (0 == ul_ref)
			this->deleteLater();

		return ul_ref;

	}

void DeviceFactory::setEnumerator(IMMDeviceEnumerator * dev_enum)
{
	device_enum = dev_enum;
	dev_enum->RegisterEndpointNotificationCallback(this);
}
